﻿#region C# Libraries

using System;
using System.Collections.Generic;

#endregion

#region XNA Libraries

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

#endregion

namespace main.sdk.input
{

    public sealed class Gamepad
    {

        #region Static

        #region Constants

        public static readonly byte UNTOUCHED = 0;
        public static readonly byte TRIGGERED = 1;
        public static readonly byte PRESSED = 2;
        public static readonly byte RELEASED = 3;

        public static readonly Gamepad[] List = new Gamepad[4];
        private static readonly Buttons[] ButtonList = (Buttons[])Enum.GetValues(typeof(Buttons));

        #endregion

        #region Constructor & Update

        static Gamepad()
        {
            for (short i = 3; i >= 0; --i) List[i] = new Gamepad((PlayerIndex)i);
            Update();
        }

        public static Gamepad Get(int Index)
        {
            return List[Index];
        }

        public static void Update() { foreach (Gamepad item in List) item.Refresh(); }

        #endregion

        #endregion

        #region Instance

        #region Variables

        public readonly PlayerIndex Index;
        public GamePadDeadZone DeadZone = GamePadDeadZone.None;
        public bool Connected = false;
        private GamePadState _State;
        public readonly Dictionary<Buttons, byte> State = new Dictionary<Buttons, byte>(ButtonList.Length);

        #endregion

        #region Constructor, Reset & Refresh

        public Gamepad(PlayerIndex index)
        {
            Index = index;
            Reset();
        }

        public void Reset() { foreach (Buttons button in ButtonList) State[button] = UNTOUCHED; }

        public void Refresh()
        {
            _State = GamePad.GetState(Index, DeadZone);
            if (_State.IsConnected)
            {
                if (Connected)
                    foreach (Buttons button in ButtonList)
                    {
                        byte buttonState = State[button];
                        State[button] = buttonState == UNTOUCHED || buttonState == RELEASED ?
                            _State.IsButtonUp(button) ? UNTOUCHED : TRIGGERED :
                            _State.IsButtonUp(button) ? RELEASED : PRESSED;
                    }
                else
                {
                    foreach (Buttons i in ButtonList) State[i] = _State.IsButtonUp(i) ? UNTOUCHED : PRESSED;
                    Connected = true;
                }
            }
            else if (Connected)
            {
                Reset();
                Connected = false;
            }
        }

        #endregion

        #region State Accessors

        public float LT { get { return _State.Triggers.Left; } }
        public float RT { get { return _State.Triggers.Right; } }
        public Vector2 LS { get { return _State.ThumbSticks.Left; } }
        public float LSX { get { return _State.ThumbSticks.Left.X; } }
        public float LSY { get { return _State.ThumbSticks.Left.Y; } }
        public Vector2 RS { get { return _State.ThumbSticks.Right; } }
        public float RSX { get { return _State.ThumbSticks.Right.X; } }
        public float RSY { get { return _State.ThumbSticks.Right.Y; } }
        public byte ButtonState(Buttons i) { return State[i]; }
        public bool Untouch(Buttons i) { return State[i] == UNTOUCHED; }
        public bool Trigger(Buttons i) { return State[i] == TRIGGERED; }
        public bool Press(Buttons i) { return State[i] == PRESSED; }
        public bool Release(Buttons i) { return State[i] == RELEASED; }
        public bool Up(Buttons i)
        {
            byte buttonState = State[i];
            return buttonState == UNTOUCHED || buttonState == RELEASED;
        }
        public bool Down(Buttons i)
        {
            byte buttonState = State[i];
            return !(buttonState == UNTOUCHED || buttonState == RELEASED);
        }

        #endregion

        #endregion

    }

}